package org.sunny.redisson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.junit.After;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.config.Config;
import org.redisson.connection.AddressResolverGroupFactory;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

//                   _ooOoo_
//                  o8888888o
//                  88" . "88
//                  (| -_- |)
//                  O\  =  /O
//               ____/`---'\____
//             .'  \\|     |//  `.
//            /  \\|||  :  |||//  \
//           /  _||||| -:- |||||-  \
//           |   | \\\  -  /// |   |
//           | \_|  ''\---/''  |   |
//           \  .-\__  `-`  ___/-. /
//         ___`. .'  /--.--\  `. . __
//      ."" '<  `.___\_<|>_/___.'  >'"".
//     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//     \  \ `-.   \_ __\ /__ _/   .-` /  /
//======`-.____`-.___\_____/___.-`____.-'======
//                   `=---='
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//         佛祖保佑       永无BUG
//
//  
// matian
// 2019.04.07
public class MyRedisClient {

    private static CountDownLatch connectedSemaphore = new CountDownLatch(100);

    // 展示手机数量
    public static String KEY_SHOW_IPHONE_NUM = "showIPhoneNum";

    // 真实手机数量
    public static String KEY_TRUE_IPHONE_NUM = "trueIPhoneNum";

    // 支付中的集合
    public static String KEY_PAYING_MAP = "payingMap";
    public static String KEY_PAYING_MAP_NOTSUCCESS = "NOTSUCCESS";
    public static String KEY_PAYING_MAP_PAYING = "PAYING";

    // 商品集合
    public static String MAP_COMMODITY = "commodity";

    // 手机初始化数量
    public static int initIPhoneNum = 100;

    @Test
    public void after() throws InterruptedException {
        Config config = new Config();
        config.setCodec(new org.redisson.client.codec.StringCodec());
        config.useSingleServer().setAddress("redis://192.168.0.105:6379");
        config.useSingleServer().setPassword("123456");
        config.useSingleServer().setConnectionPoolSize(500);
        config.useSingleServer().setIdleConnectionTimeout(10000);//如果当前连接池里的连接数量超过了最小空闲连接数，而同时有连接空闲时间超过了该数值，那么这些连接将会自动被关闭，并从连接池里去掉。时间单位是毫秒。
        config.useSingleServer().setConnectTimeout(30000);//同任何节点建立连接时的等待超时。时间单位是毫秒。
        config.useSingleServer().setTimeout(3000);//等待节点回复命令的时间。该时间从命令发送成功时开始计时。
        config.useSingleServer().setDatabase(0);
        RedissonClient redissonClient = Redisson.create(config);
        initCommodity(redissonClient);
        for (int i = 0; i < 100; i++) {
            lockConsumption(redissonClient);
        }
        // 定时任务，不停的去扫描当前正在支付中的队列
        new Thread(() -> {
            Integer num = Integer.valueOf(redissonClient.getMap(MAP_COMMODITY).get(KEY_SHOW_IPHONE_NUM).toString());
            while(num > 0){
                RMap<Object, Object> map = redissonClient.getMap(KEY_PAYING_MAP);
                Object o = map.get(KEY_PAYING_MAP_PAYING);
                if (o != null) {
                    JSONArray payingArray = JSON.parseArray(o.toString());
                    Iterator payingIterator = payingArray.iterator();
                    while (payingIterator.hasNext()) {
                        JSONObject payingItem = JSONObject.parseObject(payingIterator.next().toString());
                        String time = payingItem.getString("time");
                        LocalDateTime plaseAnOrderTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
                        LocalDateTime localDateTime = plaseAnOrderTime.plusSeconds(60 * 10);
                        if (!LocalDateTime.now().isBefore(localDateTime)){
                            Object o1 = map.get(KEY_PAYING_MAP_NOTSUCCESS);
                            JSONArray notSuccessArray = JSON.parseArray(o1.toString());
                            notSuccessArray.add(payingItem);
                            map.put(KEY_PAYING_MAP_NOTSUCCESS, notSuccessArray.toString());
                            payingIterator.remove();
                            map.put(KEY_PAYING_MAP_PAYING, payingArray.toString());
                        }
                    }
                }
                num = Integer.valueOf(redissonClient.getMap(MAP_COMMODITY).get(KEY_SHOW_IPHONE_NUM).toString());
            }
        }).start();
        connectedSemaphore.await();
    }

    @Test
    public void aaa(){
        JSONArray array = new JSONArray();
        JSONObject object = new JSONObject();
        object.put("111", "111");
        array.add(object);

        JSONObject object2 = new JSONObject();
        object2.put("222", "222");
        array.add(object2);
        Iterator iterator = array.iterator();
        System.out.println(array.size());
        while (iterator.hasNext()) {
            JSONObject next = (JSONObject) iterator.next();
            iterator.remove();
            System.out.println(array.size());
        }
    }

    /**
     * 初始化商品
     * @param redissonClient
     */
    private void initCommodity(RedissonClient redissonClient) {
        redissonClient.getMap(MAP_COMMODITY).put(KEY_SHOW_IPHONE_NUM, initIPhoneNum);
        redissonClient.getMap(MAP_COMMODITY).put(KEY_TRUE_IPHONE_NUM, initIPhoneNum);
        redissonClient.getMap(KEY_PAYING_MAP);
    }

    private void unlockConsumption(RedissonClient redissonClient) {
        new Thread(() -> {
                consumption(redissonClient);
        }).start();
    }

    private void lockConsumption(RedissonClient redissonClient) {
        new Thread(() -> {
            RLock myLock = redissonClient.getLock("myLock2");
            myLock.lock(1000, TimeUnit.DAYS);
            if (myLock.isLocked()) {
                consumption(redissonClient);
            }
            myLock.unlock();
        }).start();
    }

    private void consumption(RedissonClient redissonClient) {
        Integer integer = Integer.valueOf(redissonClient.getMap(MAP_COMMODITY).get(KEY_TRUE_IPHONE_NUM).toString());
        if (integer > 0) {
            paying(redissonClient, Thread.currentThread().getName());
            integer -- ;
            redissonClient.getMap(MAP_COMMODITY).put(KEY_TRUE_IPHONE_NUM, integer);
        }
        paySuccess(redissonClient, Thread.currentThread().getName());
        /*RMap<Object, Object> commodity = redissonClient.getMap("commodity");
        Object zhangsan = commodity.get("iPhone6s");
        Integer integer = Integer.valueOf(zhangsan.toString());
        System.out.println(integer);
        integer--;
        commodity.put("zhangsan", integer);*/
        connectedSemaphore.countDown();
    }

    private void paySuccess(RedissonClient redissonClient, String threadId){
        Object o = redissonClient.getMap(KEY_PAYING_MAP).get(KEY_PAYING_MAP_PAYING);
        JSONArray jsonArray = JSONArray.parseArray(o == null ? "" : o.toString());
        Iterator<Object> iterator = jsonArray.iterator();
        while (iterator.hasNext()) {
            JSONObject next = JSON.parseObject(iterator.next().toString());
            if (next.get("threadId").equals(threadId)) {
                iterator.remove();



            }
        }
    }

    /**
     * 标记正在支付
     * @param redissonClient
     * @param threadId
     */
    private void paying(RedissonClient redissonClient, String threadId){
        System.out.println(threadId+" \t 正在支付中");
        Object o = redissonClient.getMap(KEY_PAYING_MAP).get(KEY_PAYING_MAP_PAYING);
        JSONArray jsonArray = JSONArray.parseArray(o == null ? "" : o.toString());
        JSONObject object = new JSONObject();
        object.put("threadId", threadId);
        object.put("time", LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
        jsonArray.add(object);
        redissonClient.getMap(KEY_PAYING_MAP).put(KEY_PAYING_MAP_PAYING, jsonArray.toString());
    }



}
